﻿namespace TestTool.GUI.Utils
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml;

    internal class SoapHelper
    {
        private const string CREATED = "Created";
        private const string ENVELOPE = "Envelope";
        private const string HEADER = "Header";
        private const string NONCE = "Nonce";
        private const string PASSWORD = "Password";
        private const string PASSWORDTYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest";
        private const string PREFIX = "s";
        private const string SECURITY = "Security";
        private const string SOAPENVELOPE = "http://www.w3.org/2003/05/soap-envelope";
        private const string TYPE = "Type";
        private const string USERNAME = "Username";
        private const string USERNAMETOKEN = "UsernameToken";
        private const string WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
        private const string WSSEPREFIX = "wsse";
        private const string WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
        private const string WSUPREFIX = "wsu";

        public string ApplySecurity(string request, string username, string password, bool utcTimeStamp)
        {
            return this.ApplySecurity(request, username, password, utcTimeStamp, false);
        }

        public string ApplySecurity(string request, string username, string password, bool utcTimeStamp, bool forceUpdate)
        {
            XmlDocument document = new XmlDocument();
            try
            {
                document.LoadXml(request);
            }
            catch (Exception)
            {
                return request;
            }
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
            nsmgr.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
            nsmgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            if ((document.SelectSingleNode(string.Format("/{0}:{1}/{0}:{2}/{3}:{4}", new object[] { "s", "Envelope", "Header", "wsse", "Security" }), nsmgr) != null) && !forceUpdate)
            {
                return request;
            }
            XmlNode oldChild = document.SelectSingleNode(string.Format("/{0}:{1}/{0}:{2}", "s", "Envelope", "Header"), nsmgr);
            if ((oldChild != null) && forceUpdate)
            {
                oldChild.ParentNode.RemoveChild(oldChild);
                oldChild = null;
            }
            if (oldChild == null)
            {
                XmlNode node3 = document.SelectSingleNode(string.Format("/{0}:{1}", "s", "Envelope"), nsmgr);
                if (node3 == null)
                {
                    return request;
                }
                oldChild = document.CreateElement("s", "Header", "http://www.w3.org/2003/05/soap-envelope");
                if (node3.FirstChild != null)
                {
                    node3.InsertBefore(oldChild, node3.FirstChild);
                }
                else
                {
                    node3.AppendChild(oldChild);
                }
            }
            XmlElement newChild = document.CreateElement("wsse", "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            XmlAttribute node = document.CreateAttribute(string.Format("xmlns:{0}", "wsse"));
            node.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
            newChild.Attributes.Append(node);
            XmlAttribute attribute2 = document.CreateAttribute(string.Format("xmlns:{0}", "wsu"));
            attribute2.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
            newChild.Attributes.Append(attribute2);
            XmlElement element2 = document.CreateElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            newChild.AppendChild(element2);
            XmlElement element3 = document.CreateElement("wsse", "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            element3.InnerText = username;
            element2.AppendChild(element3);
            XmlElement element4 = document.CreateElement("wsse", "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            XmlAttribute attribute3 = document.CreateAttribute("Type");
            attribute3.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest";
            element4.Attributes.Append(attribute3);
            string nonce = this.GetNonce();
            string timestamp = this.GetTimestamp(utcTimeStamp);
            string str3 = this.GetPasswordHash(password, nonce, timestamp);
            element4.InnerText = str3;
            element2.AppendChild(element4);
            XmlElement element5 = document.CreateElement("wsse", "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            element5.InnerText = nonce;
            element2.AppendChild(element5);
            XmlElement element6 = document.CreateElement("wsu", "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            element6.InnerText = timestamp;
            element2.AppendChild(element6);
            oldChild.AppendChild(newChild);
            MemoryStream outStream = new MemoryStream();
            document.Save(outStream);
            int index = 0;
            byte[] bytes = outStream.GetBuffer();
            while (bytes[index] != 60)
            {
                index++;
            }
            outStream.Close();
            return Encoding.UTF8.GetString(bytes, index, bytes.Length - index);
        }

        protected string GetNonce()
        {
            byte[] data = new byte[0x10];
            RandomNumberGenerator.Create().GetBytes(data);
            return Convert.ToBase64String(data);
        }

        protected string GetPasswordHash(string password, string nonce, string timestamp)
        {
            HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
            List<byte> list = new List<byte>();
            list.AddRange(Convert.FromBase64String(nonce));
            list.AddRange(Encoding.UTF8.GetBytes(timestamp + password));
            return Convert.ToBase64String(algorithm.ComputeHash(list.ToArray()));
        }

        protected string GetTimestamp(bool useUtcTimestamp)
        {
            DateTime time = useUtcTimestamp ? DateTime.Now.ToUniversalTime() : DateTime.Now;
            return time.ToString("yyyy-MM-ddTHH:mm:ssZ");
        }

        public string RemoveSecurity(string request)
        {
            XmlDocument document = new XmlDocument();
            try
            {
                document.LoadXml(request);
            }
            catch (Exception)
            {
                return request;
            }
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
            nsmgr.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
            nsmgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            XmlNode oldChild = document.SelectSingleNode(string.Format("/{0}:{1}/{0}:{2}/{3}:{4}", new object[] { "s", "Envelope", "Header", "wsse", "Security" }), nsmgr);
            XmlNode node2 = document.SelectSingleNode(string.Format("/{0}:{1}/{0}:{2}", "s", "Envelope", "Header"), nsmgr);
            if ((oldChild != null) && (node2 != null))
            {
                node2.RemoveChild(oldChild);
            }
            if ((node2 != null) && (node2.ChildNodes.Count == 0))
            {
                node2.ParentNode.RemoveChild(node2);
            }
            MemoryStream outStream = new MemoryStream();
            document.Save(outStream);
            int index = 0;
            byte[] bytes = outStream.GetBuffer();
            while (bytes[index] != 60)
            {
                index++;
            }
            outStream.Close();
            return Encoding.UTF8.GetString(bytes, index, bytes.Length - index);
        }
    }
}

